package dcutils;

// Import Java JDK Classes
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A class which encapsulates a number and increments it upon each get operation.<br/>
 * An instance of this class is analogous to a database sequencer.<br/>
 * @author dca
 */
public class Sequencer {
   /** Holds the current value for this sequencer.<br/> */
   private AtomicInteger currentValue;

   /** Specifies whether to increment the <code>currentValue</code> before or after calling <code>nextValue()</code>.<br/> */
   private boolean postIncrement;

   /**
    * Creates a new sequencer.<br/>
    * This will set the <code>currentValue</code> to <i>zero</i> and the <code>postIncrement</code> to <i>true</i>.<br/>
    */
   public Sequencer() {
      this(0, true);
   } // END constructor

   /**
    * Creates a new sequencer with an initial value.<br/>
    * The <code>postIncrement</code> will be <i>true</i>.<br/>
    * @param initialValue The value to set as the <code>currentValue</code>.<br/>
    */
   public Sequencer(int initialValue) {
      this(initialValue, true);
   } // END constructor

   /**
    * Creates a new sequencer with the specified <code>postIncrement</code>.<br/>
    * The <code>currentValue</code> will be <i>zero</i>.<br/>
    * @param postIncrement True or False.<br/>
    */
   public Sequencer(boolean postIncrement) {
      this(0, postIncrement);
   } // END constructor

   /**
    * Creates a new sequencer with the specified <code>initialValue</code> and <code>postIncrement</code>.<br/>
    * @param initialValue The value to set as the <code>currentValue</code>.<br/>
    * @param postIncrement True or False.<br/>
    */
   public Sequencer(int initialValue, boolean postIncrement) {
      this.currentValue = new AtomicInteger(initialValue);
      this.postIncrement = postIncrement;
   } // END constructor

   /**
    * Returns the current sequencer value.<br/>
    * Does not increment the value.<br/>
    * @return <code>currentValue.get()</code>.<br/>
    */
   public int currentValue() {
      return currentValue.get();
   } // END currentValue

   /**
    * Returns the <code>postIncrement</code> setting.<br/>
    * @return <code>postIncrement</code> True or false.<br/>
    */
   public boolean postIncrement() {
      return this.postIncrement;
   } // END postIncrement

   /**
    * Returns the next value of the sequencer.<br/>
    * Based on <code>postIncrement</code> The sequencer will either get the value and increment or increment, then get the value; and return the value.<br/>
    * @return The sequencer value.<br/>
    */
   public int nextValue() {
      return (
         postIncrement ?
         currentValue.getAndIncrement() :
         currentValue.incrementAndGet()
      );
   } // END nextValue

   /**
    * Returns a readable representation of the sequencer.<br/>
    * Basically it is a formatted representation of the <code>currentValue</code>.<br/>
    * @return String The formatted representation of the <code>currentValue</code>.<br/>
    */
   @Override
   public String toString() {
      StringBuffer buffer = new StringBuffer(1024);
      buffer.append(this.getClass().getSimpleName()); buffer.append(" [");

      buffer.append(String.format("%s = %s", "currentValue", this.currentValue));

      buffer.append("]");
      return buffer.toString();
   } // END toString

   /**
    * Checks this sequencer for equality to another object.<br/>
    * This sequencer is considered equal to another object if
    * the other object is also a Sequencer,
    * and has the same <code>currentValue</code> and <code>postIncrement</code> setting.<br/>
    * @param obj The object to compare to this Sequencer.<br/>
    * @return <code>boolean</code> True if <code>obj</code> is a Sequencer and has the same data as this Sequencer; false otherwise.<br/>
    */
   @Override
   public boolean equals(Object obj) {
      if(null == obj) {
         return false;
      } else if(obj instanceof Sequencer) {
         Sequencer seq = (Sequencer)obj;
         return this.currentValue() == seq.currentValue() &&
                this.postIncrement() == seq.postIncrement();
      } else {
         return false;
      } // END if/else
   } // END equals

   /**
    * Generates and returns a hash code for the Sequencer.<br/>
    * The hash code is based on a prime number, the <code>currentValue</code>, and the <code>postIncrement</code>.<br/>
    * @return <code>int</code> The hash code.<br/>
    */
   @Override
   public int hashCode() {
      int hashCode = 101;
      hashCode = (11 * hashCode) + this.currentValue();
      hashCode = (11 * hashCode) + Boolean.valueOf(this.postIncrement).hashCode();
      return hashCode;
   } // END hashCode
} // END class Sequencer
